/* GameBoard.java */

package gameboard;

import player.MachinePlayer.ChipType;

public class GameBoard {
	
	private GameBoardTile[][] gameboard = new GameBoardTile[8][8];
	private int playerColour;
	
	/**
	 * Constructor for GameBoard which creates an 8 x 8 array filled with 
     * GameBoardTiles, representing the 8 x 8 gameboard. It also sets the 
     * corners and the goals of the other colour to invalid.
	 */
	public GameBoard(int color){
		playerColour = color;
		fill();
	}
	
	/**
	 * This method fills the GameBoardTile references of the GameBoard with actual 
	 * GameBoardTile objects and invalidates the corners and goals of the other colour.
	 */
	private void fill() {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				gameboard[x][y] = new GameBoardTile(x, y, true);
				if (x == 0 || x == 7) {
					gameboard[x][y].changeValidity(ChipType.BLACK);
				}
				if (y == 0 || y == 7) {
					gameboard[x][y].changeValidity(ChipType.WHITE);
				}
			}
		}
	}

	/**
	 * This method returns the current GameBoardTile in 
	 * @param x, which is the x-coordinate of the GameBoard and 
	 * @param y, which is the y-coordinate of the GameBoard
	 * @return the GameBoardTile
	 */
	public GameBoardTile getTile(int x, int y) {
		return gameboard[x][y];
	}
	
	/**
	 * This method changes the chip of the GameBoardTile at the given location to the new chip.
	 * It also checks the neighbouring GBT's to for a chip of the same colour. If there is a chip 
	 * of the same colour, then GBT will switch the validities of the neighbouring tiles to false
	 * to prevent more than two chips in a connected group, whether connected orthogonally or 
	 * diagonally
	 * @param x is the x-coordinate of the GameBoardTile
	 * @param y is the y-coordinate of the GameBoardTile
	 * @param c is the ChipType
	 */
	public void changeChip(int x, int y, ChipType c) {
		gameboard[x][y].insert(c);
		boolean check = false;
		GameBoardTile[] temp = new GameBoardTile[8];
		GameBoardTile[] gbt = getNeighbours(x, y);

		if (!(c == ChipType.EMPTY)) {
			for (GameBoardTile tile : gbt) {
				temp = getNeighbours(tile.getX(), tile.getY());
				if (tile.getChip() == c) {
					check = true;
					switchValidities(temp, c);
					break;
				} else {
					for (GameBoardTile t : temp) {
						if (t.getChip() == c && t != getTile(x, y) && tile.getValidity(c)) {
							tile.changeValidity(c);
							break;
						}
					}
				}
			}
			if (check) {
				switchValidities(gbt, c);
			}
		} else {
			if (twoNeighbour(gbt, c)) {
				getTile(x, y).changeValidity(c);
			}
		}
	}
	
	/**
	 * This method helps changeChip change the validities of neighbouring tiles to false.
	 * @param gbt is the array of neighbours.
	 * @param c is the colour of the chip.
	 */
	private void switchValidities(GameBoardTile[] gbt, ChipType c) {
		for (GameBoardTile tile : gbt) {
			if (tile.getValidity(c)) {
				tile.changeValidity(c);
			}
		}
	}
	
	/**
	 * This method returns if a chip of a given colour is valid in the given GameBoardTile
	 * @param x is the x-coordinate of the GameBoardTile
	 * @param y is the y-coordinate of the GameBoardTile
	 * @param c is the type of chip
	 * @return true if the GameBoardTile is valid, false otherwise
	 */
	public boolean getValidity(int x, int y, ChipType c) {
		// System.out.println("x is " + x + " y is " + y + " c is " + c);
		if (c == ChipType.WHITE) {
			// System.out.println("IF IN GETVALIDITY");
			return gameboard[x][y].getValidity(c);
		}
		// System.out.println("NOT IF");
		return gameboard[x][y].getValidity(c);
	}
	
	/**
	 * This method finds the neighbours around a given GameBoardTile location. If 
	 * neighbouring tiles are invalid (i.e. they are off the board), a filler GameBoardTile is 
	 * used.
	 * @param x is the x-coordinate
	 * @param y is the y-coordinate
	 * @return an array of GameBoardTiles that are the 8 neighbours around the GameBoardTile at 
	 * (x, y). If a neighbour is out of bounds, it is filled in with a filler GameBoardTile.
	 */
	public GameBoardTile[] getNeighbours(int x, int y) {
		GameBoardTile[] neighbours = new GameBoardTile[8];
		int k = 0;
		for (int i = y - 1; i <= y + 1; i++) {
			for (int j = x - 1; j <= x + 1; j++) {
				if (i == y && j == x) {
					continue;
				}
				try {
					neighbours[k] = getTile(j, i);
				} catch (ArrayIndexOutOfBoundsException e) {
					neighbours[k] = new GameBoardTile(j, i, false);
				}
				k++;
			}
		}
		return neighbours;
	}
	
	/**
	   * twoNeighbour checks to see if at two neighbours are the same chip
	   * @param n is the array of neighbours 
	   * @param c is the type of chip
	   * @return true if and only if kind appears twice in the array of neighbours,
	   * false otherwise
	   */
	private boolean twoNeighbour(GameBoardTile[] n, ChipType c) {
		int j = 0;
		boolean a = false;
		boolean b = false;
		for (int i = 0; i < n.length; i++) {
			j++;
			if (n[i].getChip() == c) {
				a = true;
				break;
			}
			if (i == n.length - 1) {
				return a;
			}
		}
		for (int i = j; i < n.length; i++) {
			if (n[i].getChip() == c) {
				b = true;
				break;
			}
		}
		return a && b;
	}
}
